/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.Utils3D;

/**
 * Simple 3D vector class.  Handles basic vector math for 3D vectors.
 */
public class Vector3 {
    public float x;
    public float y;
    public float z;

    public static final Vector3 ZERO = new Vector3(0, 0, 0);
    public static final Vector3 UNIT_X = new Vector3(1, 0, 0);
    public static final Vector3 UNIT_Y = new Vector3(0, 1, 0);
    public static final Vector3 UNIT_Z = new Vector3(0, 0, 1);
    
    public Vector3() {
    }
    
    public Vector3(float[] array)
    {
    	set(array[0], array[1], array[2]);
    }
    
    public Vector3(float xValue, float yValue, float zValue) {
        set(xValue, yValue, zValue);
    }

    public Vector3(Vector3 other) {
        set(other);
    }

    public Vector3 add(Vector3 other) {
    	Vector3 s = new Vector3();
    	
        s.x = x + other.x;
        s.y = y + other.y;
        s.z = z + other.z;
        
        return s;
    }
    
    public Vector3 add(float otherX, float otherY, float otherZ) {
    	Vector3 s = new Vector3();
    	Vector3 other = new Vector3(otherX, otherY, otherZ);
    	return s.add(other);
    }
    
    public Vector3 subtract(Vector3 other) {
    	Vector3 s = new Vector3();
    	
        s.x = x - other.x;
        s.y = y - other.y;
        s.z = z - other.z;
        
        return s;
    }
    
    public void subtractMultiple(Vector3 other, float multiplicator)
    {
        x -= other.x * multiplicator;
        y -= other.y * multiplicator;
        z -= other.z * multiplicator;
    }
    
    public Vector3 multiply(float magnitude) {
    	Vector3 s = new Vector3();
    	
        s.x = x * magnitude;
        s.y = y * magnitude;
        s.z = z * magnitude;
        
        return s;
    }
    
    public Vector3 multiply(Vector3 other) {
    	Vector3 s = new Vector3();
    	
        s.x = x * other.x;
        s.y = y * other.y;
        s.z = z * other.z;
        
        return s;
    }

    public Vector3 divide(float magnitude) {
    	Vector3 s = new Vector3();
    	if (magnitude != 0.0f) {
        	
            s.x = x / magnitude;
            s.y = y / magnitude;
            s.z = z / magnitude;          
        }
        return s;
    }

    public void set(Vector3 other) {
        x = other.x;
        y = other.y;
        z = other.z;
    }

    public void set(float xValue, float yValue, float zValue) {
        x = xValue;
        y = yValue;
        z = zValue;
    }
    
    // Given the 3 Vertex of a triangle, returns the perpendicular to this triangle (face normal)
    public static Vector3 perpendicular(Vector3 a, Vector3 b, Vector3 c) {
    	
    	Vector3 edge1 = b.subtract(a);
    	Vector3 edge2 = c.subtract(a);
    	return edge1.cross(edge2);
    	
    }

    public float dot(Vector3 other) {
        return (x * other.x) + (y * other.y) + (z * other.z);
    }
    
    public Vector3 cross(Vector3 other) {
    	return new Vector3(	y * other.z - z * other.y,
    						z * other.x - x * other.z,
    						x * other.y - y * other.x);
    }

    public float length() {
        return (float) Math.sqrt(length2());
    }

    public float length2() {
        return (x * x) + (y * y) + (z * z);
    }
    
    public float distance2(Vector3 other) {
        float dx = x - other.x;
        float dy = y - other.y;
        float dz = z - other.z;
        return (dx * dx) + (dy * dy) + (dz * dz);
    }

    public float normalize() {
        float magnitude = length();

        // TODO: I'm choosing safety over speed here.
        if (magnitude != 0.0f) {
            x /= magnitude;
            y /= magnitude;
            z /= magnitude;
        }

        return magnitude;
    }
    
    public void zero() {
        set(0.0f, 0.0f, 0.0f);
    }
    
    public boolean pointsInSameDirection(Vector3 other) {
    	return this.dot(other) > 0;
    }
    
}
